import './index.less'

import { Dropdown } from 'ant-design-vue'
import { createApp, h, ref } from 'vue'

import { hexToRgb } from '@/utils'

import DmpLabel from '../../../components/DmpLabel.vue'
import { MarkTaskLabelRes } from '../../../components/LabelCard/types'
import SelectEntityAndRelationLabel from '../../../components/SelectEntityAndRelationLabel.vue'
import { DmpLabelProps } from '../../../types/index'
import { useLabelResultListStore } from '../../store/index'
import { DEFAULT_CONFIG, DefaultConfig, EntityLabelLocationInfo } from './config'
import { CodeEnum } from './enum'
import { TextNamedEntityLabel } from './TextNamedEntityLabel'

const labelResultListStore = useLabelResultListStore()

/**
 * 三元组标注
 */
export class TextTriadLabel extends TextNamedEntityLabel {
  constructor(config: DefaultConfig = DEFAULT_CONFIG) {
    super(config)
  }

  /**
   * 创建标签
   * @param label
   * @returns 标签虚拟DOM
   */
  createTag = (label: DmpLabelProps) => {
    const selectEntityAndRelationLabelState = ref({
      modelOpen: false,
      open: false,
      labelType: 'Entity',
      entityLabel: {} as EntityLabelLocationInfo,
      entityLabelList: [] as EntityLabelLocationInfo[],
      'onUpdate:modelOpen': (val: boolean) => {
        selectEntityAndRelationLabelState.value.modelOpen = val
      },
      'onUpdate:open': (val: boolean) => {
        selectEntityAndRelationLabelState.value.open = val
      }
    })

    // 创建标签组件
    const dmpLabelEl = h(DmpLabel, {
      title: '标题',
      color: '#1868E9',
      showDropdown: false,
      ...label,
      // 监听组件内部事件
      onRemove: async () => {
        // 删除标签
        try {
          await this.removeTag(dmpLabelWrap)
          dmpLabelComponent.unmount()
        } catch {}
      },
      onClick: () => {
        const onlyId = dmpLabelWrap.getAttribute('data-only-id')
        const entityLabel = this.entityLabelLocationInfoList.find(item => item.onlyId === onlyId) || {}
        this.currentLabelWrap = dmpLabelWrap
        selectEntityAndRelationLabelState.value.open = true
        selectEntityAndRelationLabelState.value.entityLabel = entityLabel
        selectEntityAndRelationLabelState.value.entityLabelList = this.entityLabelLocationInfoList
      }
    })

    // 选择实体和关系标签组件
    const SelectEntityAndRelationLabelCompRef = ref()
    const SelectEntityAndRelationLabelComp = () => {
      return h(SelectEntityAndRelationLabel, {
        labelType: selectEntityAndRelationLabelState.value.labelType,
        ref: SelectEntityAndRelationLabelCompRef,
        taskId: this.serviceParams.taskId || '',
        entityLabel: selectEntityAndRelationLabelState.value.entityLabel,
        entityLabelList: selectEntityAndRelationLabelState.value.entityLabelList,
        // 改变实体标签
        onEntityChange: async (params: any) => {
          // 替换标签
          await this.replaceTag(dmpLabelWrap, {
            id: params.id,
            color: params.color,
            title: params.name
          })
          this.currentLabelWrap = null
          selectEntityAndRelationLabelState.value.labelType = 'Entity'
          selectEntityAndRelationLabelState.value.open = false
          dmpLabelComponent.unmount()
        },
        // 改变关系标签
        onRelationChange: async (startLabel: EntityLabelLocationInfo, endLabel: EntityLabelLocationInfo, relLabel: MarkTaskLabelRes) => {
          try {
            await labelResultListStore.addRelationResult(startLabel, endLabel, relLabel)
            selectEntityAndRelationLabelState.value.labelType = 'Entity'
            selectEntityAndRelationLabelState.value.open = false
            this.currentLabelWrap = null
          } catch (error) {
            this.updateEvent?.({
              type: 'INFO',
              message: '此结果已存在于标注结果中',
              data: null,
              code: CodeEnum.LABEL_HAS_RESULT
            })
          }
        }
      })
    }

    const dmpLabelComponent = createApp({
      render: () =>
        h(
          Dropdown,
          {
            trigger: ['click'],
            destroyPopupOnHide: true,
            open: selectEntityAndRelationLabelState.value.open,
            onOpenChange: open => {
              selectEntityAndRelationLabelState.value.labelType = 'Entity'
              window.getSelection()?.removeAllRanges()
              if (open) {
                this.currentLabelWrap = dmpLabelWrap
                this.currentLabelComponent = dmpLabelComponent
                return
              }
              selectEntityAndRelationLabelState.value.open = false
              this.currentLabelWrap = null
              this.currentLabelComponent = null
              this.currentRange = null
            }
          },
          {
            default: () => dmpLabelEl,
            overlay: SelectEntityAndRelationLabelComp
          }
        )
    })

    // 创建一个新的元素
    const dmpLabelWrap = this.createLabelWrap(label)

    // 挂载到新的元素上
    dmpLabelComponent.mount(dmpLabelWrap)

    // 监听鼠标移入事件
    dmpLabelWrap.addEventListener('mouseenter', () => {
      let prevNode = dmpLabelWrap?.previousElementSibling as any
      while (prevNode && prevNode?.nodeName === 'SPAN' && prevNode?.getAttribute('data-selection') === 'true') {
        Object.assign(prevNode.style, {
          ...this.config.labelBeforeSpanActiveStyle,
          background: hexToRgb(label?.color, 0.1)
        })
        prevNode = prevNode.previousElementSibling
      }
    })
    // 监听鼠标移出事件
    dmpLabelWrap.addEventListener('mouseleave', () => {
      this.container?.querySelectorAll('span').forEach(span => {
        span.style.background = 'transparent'
      })
    })

    return dmpLabelWrap
  }

  /**
   * 替换标签
   * @param dmpLabelWrap 需要替换的标签容器
   * @param label 标签信息
   * @param config{force: bool} 替换配置项 {force: 强制修改}
   */
  replaceTag = (dmpLabelWrap: HTMLDivElement, label: DmpLabelProps, config: { force: boolean } = { force: false }) => {
    return new Promise<any>((resolve, reject) => {
      const onlyId = dmpLabelWrap.getAttribute('data-only-id') || ''

      if (!config?.force) {
        const relationResult = labelResultListStore.relationResultList.find(item => {
          const { startLabel, endLabel } = item
          return startLabel.onlyId === onlyId || endLabel.onlyId === onlyId
        })
        if (relationResult) {
          const msg = `当前实体标签已被“${relationResult?.relationLabel?.name}”关联，请在删除标注结果后重试`
          this.updateEvent?.({
            type: 'ERROR',
            message: msg,
            data: this.entityLabelLocationInfoList,
            code: CodeEnum.LABEL_HAS_RESULT
          })
          return reject(msg)
        }
      }

      const textList: string[] = this.removeSpan(dmpLabelWrap)
      const text = this.textListWrapSpan(textList, {
        color: label.color
      })
      const tag = this.createTag({ ...label, onlyId })
      dmpLabelWrap?.replaceWith(tag)
      let index = 0
      while (index < textList.length) {
        tag.previousSibling?.remove()
        index++
      }
      tag.before(text)
      dmpLabelWrap?.remove()
      this.currentLabelWrap = null

      const labelIndex = this.entityLabelLocationInfoList.findIndex(item => item.onlyId === onlyId)
      if (labelIndex !== -1) {
        this.entityLabelLocationInfoList[labelIndex] = {
          ...this.entityLabelLocationInfoList[labelIndex],
          labelId: label.id,
          labelName: label.title,
          labelColor: label.color
        }
      }

      this.updateEvent?.({
        type: 'SUCCESS',
        message: '标签替换成功',
        data: this.entityLabelLocationInfoList,
        code: CodeEnum.SUCCESS
      })
      resolve(label)
    })
  }

  /**
   * 删除标签
   * @param node 节点
   * @param config{force: bool} 删除配置项 {force: 强制删除}
   */
  removeTag = (node: HTMLDivElement, config: { force: boolean } = { force: false }) => {
    return new Promise((resolve, reject) => {
      const onlyId = node.getAttribute('data-only-id') || ''

      if (!config?.force) {
        const relationResult = labelResultListStore.relationResultList.find(item => {
          const { startLabel, endLabel } = item
          return startLabel.onlyId === onlyId || endLabel.onlyId === onlyId
        })
        if (relationResult) {
          const msg = `当前实体标签已被“${relationResult?.relationLabel?.name}”关联，请在删除标注结果后重试`
          this.updateEvent?.({
            type: 'ERROR',
            message: msg,
            data: this.entityLabelLocationInfoList,
            code: CodeEnum.LABEL_HAS_RESULT
          })
          return reject(msg)
        }
      }

      const labelIndex = this.entityLabelLocationInfoList.findIndex(item => item.onlyId === onlyId)
      if (labelIndex !== -1) {
        this.entityLabelLocationInfoList.splice(labelIndex, 1)
      }
      this.removeSpan(node)
      node.remove()
      this.updateEvent?.({
        type: 'SUCCESS',
        message: '标签删除成功',
        data: this.entityLabelLocationInfoList,
        code: CodeEnum.SUCCESS
      })
      resolve(this.entityLabelLocationInfoList)
    })
  }
}
